<?
/**
 * This file is part of XNAT light.
 *
 * XNAT light is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * XNAT light is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XNAT light.  If not, see <http://www.gnu.org/licenses/>.
 */
namespace NRG\Database\Mappers;

use NRG\Xnat as Xnat;
use NRG\Framework\Exceptions\IllegalArgumentException as IllegalArgumentException;
use NRG\Framework\Exceptions\QueryException as QueryException;

/**
 * Subject database mapper
 *
 * @package NRG\Database\Mappers
 */
class Subject extends Mapper
{
    /**
     * Accession ID
     *
     * @var string
     */
    protected $_id;

    /**
     * Constructor
     */
    public function __construct()
    {
	parent::__construct();
    }

    /**
     * Access Subject by ID
     *
     * @param string $id Subject accession ID
     * @return NRG\Xnat\Subject
     */
    public function byId($id=null)
    {
	// input validation
	if(!is_string($id))
	    throw new IllegalArgumentException("Accession ID must be a string");
	else if($id == "")
	    throw new IllegalArgumentException("Accession ID cannot be null");

	$subjects = $this->byList(array($id));

	return current($subjects);
    }

    /**
     * Get Subject info by Subject label and project
     *
     * @param string $label
     * @param string $project
     */
    public function infoByLabel($label, $project)
    {
	$query = "SELECT xnat_subjectdata.id AS aid, xnat_subjectdata.label AS label,
	    xnat_projectdata.id AS pid, xnat_projectdata.name AS plabel FROM xnat_subjectdata
	    JOIN xnat_projectdata ON (xnat_subjectdata.project=xnat_projectdata.id) WHERE xnat_subjectdata.label=$1 AND
	    (xnat_subjectdata.project=$2 OR xnat_projectdata.name=$2);";

	$result = $this->_xnat->query($query, array($label, $project));

	if(count($result) == 0)
	    return null;
	
	return $result[0];
    }

    /**
     * Get Subject info by Subject accession ID
     * 
     * @param string $id
     */
    public function infoByID($id=null)
    {
	$query = "SELECT xnat_subjectdata.id AS aid, xnat_subjectdata.label AS label,
	    xnat_projectdata.id AS pid, xnat_projectdata.name AS plabel FROM xnat_subjectdata
	    JOIN xnat_projectdata ON (xnat_subjectdata.project=xnat_projectdata.id)";

	if (!empty($id))
		$query.=' WHERE xnat_subjectdata.id=$1';

	$result = $this->_xnat->query($query, array($id));

	if(count($result) == 0)
	    return null;
	elseif (!empty($id))
	    return $result[0];

	return $result;
    }

    /**
     * Retrieve an array of Subject object
     *
     * @param array $list
     * @return array (string, NRG\Xnat\Subject)
     * @throws QueryException
     */
    public function byList(array $list)
    {
	$numItems = count($list);

	if ($numItems == 0)
	    throw new IllegalArgumentException("List cannot be empty");

	/**
	 * Retrieve general subject information
	 */
	// build IN list
	$in_clause = "(";
	for($i = 1; $i <= $numItems; $i++)
	    $in_clause .= "$" . $i . ",";
	$in_clause = rtrim($in_clause, ",");
	$in_clause .= ")";

	$query = "SELECT id,label,project FROM xnat_subjectdata WHERE id IN $in_clause";

	$result = $this->_xnat->query($query, $list);

	if(count($result) == 0)
	    throw new QueryException(QueryException::EMPTY_RESULT, $query, $list);

	$subjects = array();

	foreach($result as $row)
	{
	    $id = $row["id"];
	    $subjects[$id] = new Xnat\Subject();
	    $subjects[$id]->setID($row["id"]);
	    $subjects[$id]->setLabel($row["label"]);
	    $subjects[$id]->setProjectName($row["project"]);
	}

	/**
	 * Add experiments
	 */
	$query = "SELECT subject_id,id FROM xnat_subjectassessordata WHERE subject_id IN $in_clause";
	$result = $this->_xnat->query($query, $list);

	foreach ($result as $row)
	    $subjects[$row["subject_id"]]->addExperiment($row["id"]);

	return $subjects;
    }

    /**
     * Get Subject ID given Subject label
     *
     * @param string $label
     * @param string $project
     * @return string
     */
    public function getAccessionIDs($label=null, $project=null)
    {
	if(!is_string($label))
	    throw new IllegalArgumentException("Label must be a string");
	else if(trim($label) == "")
	    throw new IllegalArgumentException("Label cannot be empty");

	$params = array($label);
	$query = "SELECT id FROM xnat_subjectdata WHERE label=$1";

    if (!empty($project))
    {
        $params[]=$project;
        $query.=" AND project=$2";
    }

	$result = $this->_xnat->query($query, $params);

	$ids = array();

	foreach($result as $row)
	    $ids[] = $row["id"];

	return $ids;
    }

    /**
     * Get Subject insert info
     *
     * @param string $id
     * @return string
     */
    public function getInsertInfo($id=null)
    {
	$result=Array();
	$params=Array();

	$query="SELECT s.label, s.project, u.login,m.insert_date,m.status 
		FROM xdat_user u, xnat_subjectdata s, xnat_subjectdata_meta_data m 
		WHERE u.xdat_user_id=m.insert_user_xdat_user_id 
		AND s.subjectdata_info=m.meta_data_id 
		AND s.project IS NOT NULL";

	if (!empty($id))
	{
	    if(!is_string($id))
	        throw new IllegalArgumentException("ID must be a string");
	    else if(trim($id) == "")
	        throw new IllegalArgumentException("ID cannot be empty");

	    $params = array($id);
		
	    $query.=' AND s.id=$1';
	}

        $qresult = $this->_xnat->query($query, $params);

	if(sizeof($qresult) == 0)
	    return null;

	foreach ($qresult as $row)
	    $result[]=$row;


	return $result;
    }



    /**
     * Get Subject labels given ID
     *
     * @param string $id
     * @return string
     */
    public function getLabel($id=null)
    {
	if(!is_string($id))
	    throw new IllegalArgumentException("ID must be a string");
	else if(trim($id) == "")
	    throw new IllegalArgumentException("ID cannot be empty");

	$params = array($id);
	$query = "SELECT label FROM xnat_subjectdata WHERE id=$1";
	$result = $this->_xnat->query($query, $params);

	if(sizeof($result) > 1)
	    throw new QueryException(QueryException::MULTI_ROW, $query, $params);
	else if(sizeof($result) == 0)
	    return null;

	$row = current($result);
	return $row["label"];
    }

    /**
     * Get Subject label given a wildcard
     *
     * @param string $wildcard
     * @return array
     */
    public function getWildcardLabels($wildcard)
    {
	if(!is_string($wildcard))
	    throw new IllegalArgumentException("Wildcard must be a string");
	else if(trim($wildcard) == "")
	    throw new IllegalArgumentException("Wildcard cannot be empty");

	$params = array($wildcard);
	$query = "SELECT label from xnat_subjectdata WHERE label LIKE $1";
	$result = $this->_xnat->query($query, $params);

	$labels = array();

	foreach($result as $row)
	    $labels[] = $row["label"];

	return $labels;
    }

    /**
     * Get Subject IDs given a wildcard label
     *
     * @param string $wildcard
     * @return array
     */
    public function getWildcardIDs($wildcard)
    {
	if(!is_string($wildcard))
	    throw new IllegalArgumentException("Wildcard must be a string");

	$params = array($wildcard);
	$query = "SELECT id from xnat_subjectdata WHERE id LIKE $1";
	$result = $this->_xnat->query($query, $params);

	$ids = array();

	foreach($result as $row)
	    $ids[] = $row["id"];

	return $ids;
    }

    public function setDateAdded($id,$value)
    {
        if (!is_string($id))
            throw new IllegalArgumentException("Subject ID must be a string");

        if (!is_string($value))
            throw new IllegalArgumentException("New subject insert date must be a string");

        $id=trim($id);
        if (empty($id))
            throw new IllegalArgumentException("Subject ID cannot be empty");

        $value=trim($value);
        if (empty($value))
            throw new IllegalArgumentException("Date cannot be empty");

        //Check for illegal characters
        if (strlen($value)!==strspn($value,"0123456789:- "))
            throw new IllegalArgumentException("The format of the date parameter is 'YYYY-MM-DD hh:mm:ss'");

        $params=Array($id);
        $query="UPDATE xnat_subjectdata_meta_data SET insert_date=timestamp '$value', activation_date=timestamp '$value' WHERE meta_data_id=(SELECT subjectdata_info FROM xnat_subjectdata WHERE id=$1 LIMIT 1)";

        $result=$this->_xnat->query($query,$params);
    }

    public function setAddedByUser($id,$userid)
    {
        if (!is_string($id))
            throw new IllegalArgumentException("Subject ID must be a string");

        if (!is_numeric($userid))
            throw new IllegalArgumentException("New user id must be numeric");

        $params=array($id,$userid);
        $query="UPDATE xnat_subjectdata_meta_data SET insert_user_xdat_user_id=$2, activation_user_xdat_user_id=$2 WHERE meta_data_id=(SELECT subjectdata_info FROM xnat_subjectdata WHERE id=$1 LIMIT 1)";

        $result=$this->_xnat->query($query,$params);
    }
}
